/**
 *******************************************************************************
 * @file commun_protocol.h
 * @author .ISS_AUTO (hudandan@issauto.com)
 * @date 2023-12-25   1. 修改bug: little2big_32()数据类型定义错误；
 *       2024-05-04   1. 优化数据类型；
 *                    2. 优化接收超时计时器的兼容性；
 *       2024-06-18   1. 修复接收超时计时器BUG；
 *       2025-04-25   1. 新增 CRC16校验函数：cal_crc16_xmodem()；
 *
 * @brief  This file for User community handle.
 *
 * @note   1. 使用时，需要注意大小端问题！！！
 *
 * @copyright Copyright (c) 2023 ISSAUTO TECH Co., Ltd. All rights reserved.
 *
 *******************************************************************************
 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USER_COMM_PROTOCOL_H
#define __USER_COMM_PROTOCOL_H

#ifdef __cplusplus
extern "C" {
#endif

/* Exported Includes ---------------------------------------------------------*/
#include "main.h"
#include "commun_util.h"

/* Exported macro ------------------------------------------------------------*/

/*!< Protocol Format <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
#define FRAME_BIG_ENDIAN                (0U) //!< 大端模式(Big-Endian): 数据的高位字节存放在内存的高地址端，低位字节位存放在内存的低地址端。
#define FRAME_LITTLE_ENDIAN             (1U) //!< 小端模式(Little-Endian): 数据的低位字节存放在内存的高地址端，高位字节位存放在内存的低地址端。

#define FRAME_ENDIAN                    FRAME_BIG_ENDIAN

/*!< Protocol Format Config <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
/* 帧元素【数据长度位】使能设置 */
#define PROTOCOL_ELEMENT_LEN_ENABLE     (1)

/* 帧元素【功能码位】使能设置 */
#define PROTOCOL_ELEMENT_CMD_ENABLE     (1)

/* 帧元素【校验位】使能设置 */
#define PROTOCOL_ELEMENT_CK_ENABLE      (1)

/* 帧元素【结束位】使能设置 */
#define PROTOCOL_ELEMENT_ETX_ENABLE     (0)

/* 帧元素最大Size */
#define MAX_ELEMENT_SIZE_CP             (2U)


/* Exported types ------------------------------------------------------------*/

/** @addtogroup User Protocol analyze
  * @{
  */

typedef int  (* rcv_analyze)(unsigned char const rdata, void *arg);
typedef void (* rcv_frame_check)(unsigned char *buf, unsigned int bufLen, unsigned char *ret, unsigned char retLen);
typedef int (* rcv_frame_handler)(void *arg);

struct _ProtocolElement {
    unsigned int  offset;
    unsigned char dataLen;
    unsigned char data[MAX_ELEMENT_SIZE_CP];
}; /* Frame base element type */

typedef struct _protocol_data_t {
    struct _ProtocolElement stx;     //<! 起始位
    #if (PROTOCOL_ELEMENT_LEN_ENABLE)
    struct _ProtocolElement len;     //<! 数据长度
    #endif
    #if (PROTOCOL_ELEMENT_CMD_ENABLE)
    struct _ProtocolElement cmd;     //<! 功能码
    #endif
    #if (PROTOCOL_ELEMENT_CK_ENABLE)
    struct _ProtocolElement ck;      //<! 校验
    #endif
    #if (PROTOCOL_ELEMENT_ETX_ENABLE)
    struct _ProtocolElement etx;     //<! 结束位
    #endif
} protocol_data_t;

struct _protocol_analyze_t {
    rcv_analyze       analyze_handler; //<! 接收解析函数
    rcv_frame_check   frame_check;     //<!< Check
    rcv_frame_handler frame_handler;   //<! 帧处理函数

    unsigned int rcv_timer;   //<! 接收超时定时器
    unsigned short count;     //<! 有效字节接收计数
    unsigned short frameLen;  //<! 接收数据帧总长
    #if (PROTOCOL_ELEMENT_LEN_ENABLE) && (!PROTOCOL_ELEMENT_ETX_ENABLE)
    unsigned short headLen;   //<! 帧头长度(!!! 只在len使能etx禁能时有效)
    #endif
    unsigned int rcvbufLen;   //<! 接收缓存区长度
    unsigned char *rcvbuf;    //<! 接收缓存区

    struct _protocol_data_t  *pElement;
};

struct _Protocol_Info_t {
    unsigned int (*write)(const void *buf, unsigned int len); //<! 发送接口
    unsigned int (*read)(void *buf, unsigned int len);        //<! 接收接口
    struct _protocol_analyze_t analyze;

    void                       *userdata;

}; /*<! user protocol information */

/**
  * @}
  */

/* Exported constants --------------------------------------------------------*/

/* Protocol Receive Fault Code */
#define	USER_PROTOCOL_RECV_FAULT_INVALID_VALUE      (-5) //!< 无效参
#define	USER_PROTOCOL_RECV_FAULT_INVALID_ADDR       (-4) //!< 无效地址
#define	USER_PROTOCOL_RECV_FAULT_INVALID_DATA       (-3) //!< 无效数据
#define	USER_PROTOCOL_RECV_FAULT_RECEIVE            (-2) //!< 接收错误
#define	USER_PROTOCOL_RECV_FAULT_CHECK              (-1) //!< 解析错误
#define	USER_PROTOCOL_RECV_IDLE                     (0)  //!< 空闲
#define	USER_PROTOCOL_RECV_SUCCESS                  (1)  //!< 成功
#define	USER_PROTOCOL_RECV_FAULT                    (2)  //!< 通信错误
#define	USER_PROTOCOL_RECV_BUSY                     (3)  //!< 设备忙碌中
#define	USER_PROTOCOL_RECV_GOT_HEAD                 (4)  //!< 识别通信帧头
#define	USER_PROTOCOL_RECV_TIMEOUT                  (5)  //!< 超时


/* Frame Fault Code */
#define	USER_FRAME_FAULT_INVALID_VALUE              (-4) //!< 无效参
#define	USER_FRAME_FAULT_INVALID_ADDR               (-3) //!< 无效地址
#define	USER_FRAME_FAULT_INVALID_DATA               (-2) //!< 无效数据
#define	USER_FRAME_FAULT                            (-1) //!< 解析错误
#define	USER_FRAME_SUCCESS                          (0)  //!< 成功

/* Exported variables --------------------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/
extern unsigned int little2big_32(unsigned int le);
extern unsigned int big2little_32(unsigned int be);
extern unsigned short little2big_16(unsigned short le);
extern unsigned short big2little_16(unsigned short be);

#if (0)
/**
 * @brief 计算校验和
 *
 * @param[in] pBuf 待校验缓冲区
 * @param[in] pBufLen 待校验缓冲区长度
 * @param[out] ret 校验结果
 * @param[out] retLen 校验结果长度
 * @return none
 */
extern void cal_checksum(unsigned char *pBuf, unsigned int pBufLen, unsigned char *ret, unsigned char retLen);
#endif

#if (1)
/**
 * @brief CRC-16(x16+x15+x2+1) - MODBUS
 *
 * @param[in] pBuf 待校验缓冲区
 * @param[in] pBufLen 待校验缓冲区长度
 * @param[out] ret 校验结果
 * @param[out] retLen 校验结果长度
 * @return none
 */
extern void cal_crc16_modbus(unsigned char *pBuf, unsigned int pBufLen, unsigned char *ret, unsigned char retLen);
#endif

#if (1)
/**
 * @brief CRC-16(x16+x12+x5+1) - XMODEM
 *
 * @param[in] pBuf Pointer to the buffer to be checked
 * @param[in] pBufLen Length of the buffer to be checked
 * @param[out] ret Pointer to the check result
 * @param[out] retLen Length of the check result
 * @return none
 */
extern void cal_crc16_xmodem(unsigned char *pBuf, unsigned int pBufLen, unsigned char *ret, unsigned char retLen);
#endif

/**
 * @brief BaseTick Counter
 *
 * @param[in] arg Data to pass to the function
 * @return[out] void
 */
extern void User_Protocol_TimerCallback(void *arg);

/**
 * @brief Receive data handler
 *
 * @param[in] pBuf pointer to receive buffer
 * @param[in] pBufSize Size of the receive buffer
 * @param[in] arg Data to pass to the function
 * @return[out] int
 */
extern int User_Protocol_Recv_Process(unsigned char *pBuf, unsigned int pBufSize, void *arg);



#ifdef __cplusplus
}
#endif

#endif /* __USER_COMM_PROTOCOL_H */

/* END OF FILE ---------------------------------------------------------------*/
